var gfxX = (function () {
	var gfxX_animators = {};

	var gfxX_animationQueue = [];
	var gfxX_CLOSING = 0;
	var gfxX_OPENING = 1;
	var gfxX_CLOSED = 2;
	var gfxX_OPEN = 3;
	function Animator(_chanDiv, channelObj) {
		try {
			this._chanDiv = _chanDiv;
			this.onSetup(channelObj);
		} catch (e) {
			log(__FUNCTION() + "\n" + e.message);
		}
		this.timerOpen = null;
		this.timerClose = null;
	}
	Animator.prototype.onSetup = function (channelObj) {
		var shown = prefs.channels.maxProgramsOnRender;
		var cap = channelObj.program.length < prefs.channels.maxProgramsInTotal ? channelObj.program.length : prefs.channels.maxProgramsInTotal;
		this._openHeight = view_lineHeight * cap + view_logoHeight;
		this._closedHeight = view_lineHeight * prefs.channels.maxProgramsOnRender + view_logoHeight;
		this._stepHeights = [];
		this.page = this._chanDiv.parentElement;
		this.state = gfxX_CLOSED;
		var totalsteps = cap * 12 - shown * 12, nextStep = view_logoHeight;
		var diff = this._openHeight - this._closedHeight;
		this._stepHeights.push(this._closedHeight);
		nextStep = this._closedHeight;
		for (j = 0; j < totalsteps; j++) {
			nextStep += 1;
			this._stepHeights.push(nextStep);
		}
		this.id = mangleChanId(channelObj.name);
		gfxX_animators[this.id] = this;
		var a = this._chanDiv.appendElement("<a height=\"21\" width=\"100\" x=\"0\" y=\"0\"> </a>");
		var self = this;
		a.onclick = function () {
			gfxX_animators[self.id].toggle();
		};

		this.step = 0;
	};

	Animator.prototype.open = function () {
		this.state = gfxX_OPENING;
		this.start();
	};

	Animator.prototype.close = function () {
		this.state = gfxX_CLOSING;
		this.start();
	};

	Animator.prototype.toggle = function () {
		switch (this.state) {
			case gfxX_CLOSING:
				clearInterval(this.timerClose);
				this.state = gfxX_OPENING;
				break;
			case gfxX_CLOSED:
				this.state = gfxX_OPENING;
				break;
			case gfxX_OPENING:
				clearInterval(this.timerOpen);
				this.state = gfxX_CLOSING;
				break;
			case gfxX_OPEN:
				this.state = gfxX_CLOSING;
				break;
			default:
				;
		}
		this.start();
	};

	Animator.prototype.start = function () {
		if (gfxX_animationQueue.length > 0 && gfxX_animationQueue[0] !== this) {
			gfxX_animationQueue.push(this);
			return;
		} else if (gfxX_animationQueue.length == 0) {
			gfxX_animationQueue.push(this);
		}
		var self = this, i = 0;
		var animation = function () {
			if (typeof self._stepHeights[self.step] == "undefined") {
				self.done();
				return;
			}
			self.calcPositions();
			switch (self.state) {
				case gfxX_CLOSING:
					self.step--;
					if (typeof self._stepHeights[self.step] != "undefined") {
					self._chanDiv.height = self._stepHeights[self.step];
				}
				self.timerClose = setTimeout(animation, 20);
					break;
				case gfxX_OPENING:
					self.step++;
					if (typeof self._stepHeights[self.step] != "undefined") {
					self._chanDiv.height = self._stepHeights[self.step];
				}
				self.timerOpen = setTimeout(animation, 20);
				default:
					;
			}
		};

	switch (this.state) {
		case gfxX_CLOSED:case gfxX_CLOSING:
			this.step -= 1;
			this.timerClose = setTimeout(animation, 30);
			break;
		case gfxX_OPEN:case gfxX_OPENING:
			this.step += 1;
			this.timerOpen = setTimeout(animation, 30);
			break;
		default:
			;
	}
};

Animator.prototype.calcPositions = function () {
	var iter = new Enumerator(this.page.children);
	var _chanDiv;
	var pageElements = [];
	var thisIndex, i = 0;
	var differentialHeight = this._stepHeights[this.step];
	differentialHeight -= this._stepHeights[this.state == gfxX_CLOSING ? this.step + 1 : this.step - 1];
	var totalHeight = 0;
	if (/Na/.test(differentialHeight)) {
		return;
	}while (!iter.atEnd()) {
		_chanDiv = iter.item();
		pageElements.push(_chanDiv);
		totalHeight += _chanDiv.height + 3;
		if (typeof thisIndex == "undefined" && _chanDiv === this._chanDiv) {
			thisIndex = i;
		}
		iter.moveNext();
		i++;
	}
	if (totalHeight > xml_mainContainer.height) {
		resize(view.height + (totalHeight - xml_mainContainer.height));
	} else if (totalHeight < xml_mainContainer.height) {
		resize(view.height + (totalHeight - xml_mainContainer.height));
	}
	for (i = thisIndex + 1; i < pageElements.length; i++) {
		pageElements[i].y = pageElements[i].y + differentialHeight;
	}
	};

Animator.prototype.done = function () {
	switch (this.state) {
		case gfxX_CLOSING:
			this.state = gfxX_CLOSED;
			this.step = 0;
			this._chanDiv.height = this._closedHeight;
			clearTimeout(this.timerClose);
			break;
		case gfxX_OPENING:
			this.state = gfxX_OPEN;
			this.step = this._stepHeights.length - 1;
			this._chanDiv.height = this._openHeight;
			clearTimeout(this.timerOpen);
			break;
		default:
			;
	}
	gfxX_animationQueue.shift();
	if (gfxX_animationQueue.length > 0) {
		gfxX_animationQueue[0].start();
	}
};

return {
	create:function gfxX_create(c, o) {
		return new Animator(c, o);
	}
};

})();